﻿using System;
using System.Collections.Generic;

namespace Aeon.Framework.States
{

/// <summary>
/// Controller class for all state operations and persistence.
/// Can be disabled at creation time to reduce overhead.
/// 
/// </summary>    
internal class StateController
    {
    // --- Attributes:

    private Boolean enabled;                    // Enables or disables state control.

    private Queue<Command> pending;             // Pending commands list. For World consumption.
    private Queue<Command> commands;            // Commands memory ordered list.
    private Queue<Snapshot> states;             // States memory ordered list.

    private Savestate current;                  // Last savestate.

    // --- Properties:

    public Boolean Enabled { get { return(enabled); } }

    // --- Constructor:

    public StateController(bool enabled = false)
        {
        this.enabled = enabled;
        
        if (enabled)
            {
            pending = new Queue<Command>();
            commands = new Queue<Command>();
            states = new Queue<Snapshot>();
            }
        }

    // --- Public Interface:

    /// <summary>
    /// Queues received command in the execution pool.
    /// 
    /// </summary>
    public void Enqueue(Command cmd)
        {
        if (enabled) pending.Enqueue(cmd);
        }

    /// <summary>
    /// Gets command from execution pool, and records its execution.
    /// 
    /// </summary>
    public Command Dequeue()
        {
        if (!(enabled && pending.Count != 0)) return(null);
        else {
             Command cmd = pending.Dequeue();
             commands.Enqueue(cmd);
             return(cmd);
             }
        }

    /// <summary>
    /// Creates and persists savestate.
    /// Appends the single current state to the end of the current savestate.
    /// 
    /// </summary>
    public void QuickSave(String file)
        {
        if (enabled)
            {
            if (states.Count == 0) create();
            if (commands.Count != 0)
                {
                states.Enqueue(flatten(commands));
                commands.Clear();
                }

            if (states.Count == 2) states.Enqueue(squeeze(states.Dequeue(),states.Dequeue()));
        
            saveFile(file,appendState(states.Dequeue()));
            }
        }

    /// <summary>
    /// Creates and persists savestate.
    /// Remakes the current savestate with a single consolidated state.
    /// 
    /// </summary>
    public void FullSave(String file)
        {
        if (enabled)
            {
            if (states.Count == 0) create();
            if (commands.Count != 0)
                {
                states.Enqueue(flatten(commands));
                commands.Clear();
                }

            Queue<Snapshot> old = new Queue<Snapshot>();
            old.Enqueue(loadState(current));

            if (states.Count == 2) old.Enqueue(squeeze(states.Dequeue(),states.Dequeue()));
            else old.Enqueue(states.Dequeue());

            states = new Queue<Snapshot>();
            states.Enqueue(squeeze(old.Dequeue(),old.Dequeue()));

            saveFile(file,writeState(states.Dequeue()));
            }
        }

    /// <summary>
    /// Ignores any current state and loads the savestate into the pending queue.
    /// 
    /// </summary>
    public void FullLoad(String file)
        {
        if (enabled)
            {
            states.Clear();
            commands.Clear();
            
            current = loadFile(file);
            pending = expand(loadState(current));
            }
        }

    // --- Internal Helpers

    // State Management:

    /// <summary>
    /// Decomposes a snapshot into a list of commands.
    /// 
    /// </summary>
    private Queue<Command> expand(Snapshot snap)
        {
        Queue<Command> cmd = new Queue<Command>();
        
        // [TODO]
        
        return(cmd);
        }

    /// <summary>
    /// Composes a snapshot from partial commands.
    /// 
    /// </summary>
    /// <param name="commands"></param>
    private Snapshot flatten(Queue<Command> cmd)
        {
        Snapshot snap = null;

        // [TODO]
        
        return(snap);
        }

    /// <summary>
    /// Merges two snapshots in the given order.
    /// 
    /// </summary>
    private Snapshot squeeze(Snapshot first, Snapshot second)
        {
        Snapshot snap = null;

        // [TODO]
        
        return(snap);
        }

    /// <summary>
    /// Creates an empty snapshot from baseline information.
    /// 
    /// </summary>
    private Snapshot create()
        {
        Snapshot snap = null;

        // [TODO]
        
        return(snap);
        }

    // Savestate Management:

    /// <summary>
    /// Creates a new savestate for the snapshot.
    /// 
    /// </summary>
    private Savestate writeState(Snapshot full)
        {
        //current = full;
        // [TODO]

        return(null);
        }

    /// <summary>
    /// Appends savestate with another snapshot.
    /// 
    /// </summary>
    private Savestate appendState(Snapshot partial)
        {
        // current += partial;
        // [TODO]

        return(null);
        }

    /// <summary>
    /// Recreates state from a single-snapshot or multi-snapshot savestate.
    /// 
    /// </summary>
    private Snapshot loadState(Savestate ss)
        {
        // [TODO]

        return(null);
        }

    // File Management:

    /// <summary>
    /// Writes savestate to file.
    /// 
    /// </summary>
    private void saveFile(String file, Savestate ss)
        {
        // [TODO]

        }

    /// <summary>
    /// Reads savestate from file.
    /// 
    /// </summary>
    private Savestate loadFile(String file)
        {
        // [TODO]

        return(null);
        }

    }


}
